package org.abettor.octopus.worker;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.abettor.octopus.data.AuthenticationList;
import org.abettor.octopus.data.AuthenticationPair;
import org.abettor.octopus.ui.proxy.MainDialogProxy;
import org.abettor.octopus.util.DriverFinder;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.MessageBox;

/**
 * 破解线程的调度线程
 * @author abettor
 *
 */
public class Dispatcher extends Thread
{
	/**
	 * 调度线程正在等待运行
	 */
	public static final int READY = 0;
	/**
	 * 调度线程正在运行中
	 */
	public static final int RUNNING = 1;
	/**
	 * <p>破解工作被冻结</p>
	 * <p><b>注意：</b>这并不意味着调度线程已经终止</p>
	 */
	public static final int FREEZEN = 2;
	/**
	 * 调度线程已经终止
	 */
	public static final int STOPPED = 3;

	private boolean stopSignal = false;
	private boolean freezeSignal = false;
	private int status = READY;
	private List<Cracker> crackerList = new ArrayList<Cracker>();
	private String url;
	private String driverClass;
	private AuthenticationList authList = new AuthenticationList();
	private int totalSize;
	private MainDialogProxy proxy;

	/**
	 * 构造函数
	 * @param proxy 主窗口的操作行为代理类对象
	 */
	public Dispatcher(MainDialogProxy proxy)
	{
		this.proxy = proxy;
	}

	/**
	 * @see java.lang.Thread#start()
	 */
	public void start()
	{
		if(! initializeDriver())
		{
			proxy.setAccomplished();
			return;
		}

		stopSignal = false;
		super.start();
	}

	/**
	 * 终止调度线程
	 * @see java.lang.Thread#stop()
	 *
	 */
	public void end()
	{
		stopSignal = true;
	}

	/**
	 * 冻结调度线程，同时停止所有破解线程
	 *
	 */
	public void freeze()
	{
		freezeSignal = true;
	}

	/**
	 * 解冻调度线程，同时恢复所有破解线程的工作
	 *
	 */
	public void thaw()
	{
		freezeSignal = false;
	}

	/**
	 * @see java.lang.Thread#run()
	 */
	public void run()
	{
		//	线程刚刚启动时，读取字典
		if(status == READY)
		{
			//	读取字典
			if(! makeAuthenticationList())
			{
				MessageBox msg = new MessageBox(proxy.getMainShell(), SWT.OK);
				msg.setText("Error ...");
				msg.setMessage("There is something wrong when reading dictionary files.");
				msg.open();
				end();
			}
		}

		//	调度线程主体
		while(! stopSignal)
		{
			if(freezeSignal)
			{
				//	一旦冻结调度线程，就停止所有破解线程
				if(status != FREEZEN)
				{
					stopCrackers();
					status = FREEZEN;
				}
			}
			else
			{
				//	在线程为非冻结状态时，如果发现是刚刚启动的线程，或者是由冻结状态变成解冻状态，就启动破解线程
				if(status == FREEZEN || status == READY)
				{
					//	读取需要启动的破解线程数并启动相应的线程
					int threads = proxy.getThreadNumber();
					startCrackers(threads);
					status = RUNNING;
				}

				//	如果所有破解线程都已结束，则意味着破解工作已完成
				boolean flag = false;
				Iterator it = crackerList.iterator();
				while(it.hasNext())
				{
					Cracker cracker = (Cracker) it.next();
					flag = flag || cracker.isActive();
				}
				if(! flag)
				{
					end();
				}
			}

			//	显示进度
			int percent;
			if(totalSize <= 0)
			{
				percent = 100;
			}
			else
			{
				percent = (totalSize - authList.getSize()) * 100 / totalSize;
			}
			proxy.setProgress(percent);

			//	休息
			try
			{
				Thread.sleep(20);
			}
			catch (InterruptedException e)
			{
				//e.printStackTrace();
			}
		}

		stopCrackers();
		status = STOPPED;
		proxy.setAccomplished();
	}

	/**
	 * 检查调度线程的当前状态
	 * @return READY/RUNNING/FREEZEN/STOPPED
	 */
	public int getStatus()
	{
		return status;
	}

	//	启动指定个数的破解线程
	private void startCrackers(int threads)
	{
		for(int i = 0; i < threads; i ++)
		{
			Cracker cracker = new Cracker(proxy, url, authList);
			cracker.start();
			crackerList.add(cracker);
		}
	}

	//	终止所有破解线程
	private void stopCrackers()
	{
		Iterator it = crackerList.iterator();
		while(it.hasNext())
		{
			Cracker cracker = (Cracker) it.next();
			cracker.end();
		}

		while(true)
		{
			it = crackerList.iterator();
			if(! it.hasNext())
			{
				return;
			}

			Cracker cracker = (Cracker) it.next();
			if(! cracker.isActive())
			{
				crackerList.remove(cracker);
				continue;
			}

			try
			{
				Thread.sleep(20);
			}
			catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}
	}

	//	明确并加载驱动程序类，同时验证数据库连接字符串的正确性
	private boolean initializeDriver()
	{
		url = proxy.getConnectionString();
		String connector = proxy.getConnector();
		driverClass = DriverFinder.getDriverName(connector);
		Class clazz = null;
		try
		{
			clazz = Class.forName(driverClass);
		}
		catch (ClassNotFoundException e)
		{
			e.printStackTrace();

			//	显示驱动程序类错误的对话框
			MessageBox msg = new MessageBox(proxy.getMainShell(), SWT.OK);
			msg.setText("Error ...");
			msg.setMessage("No driver class specified by the connector name was found within current CLASSPATH.");
			msg.open();

			return false;
		}

		Driver driver = null;
		try
		{
			driver = DriverManager.getDriver(url);
		}
		catch (SQLException e)
		{
			e.printStackTrace();

			//	显示数据库连接字符串错误的对话框
			MessageBox msg = new MessageBox(proxy.getMainShell(), SWT.OK);
			msg.setText("Error ...");
			msg.setMessage("Can't load the driver for the specified database's URL.");
			msg.open();

			return false;
		}

		if(! clazz.isInstance(driver))
		{
			//	显示驱动程序类与数据库连接字符串不匹配的对话框
			MessageBox msg = new MessageBox(proxy.getMainShell(), SWT.OK);
			msg.setText("Error ...");
			msg.setMessage("The driver specified by the configuration and the one which is loaded according to the database's URL are mismatched.");
			msg.open();

			return false;
		}

		return true;
	}

	//	读取字典文件，生成验证信息对列表
	private boolean makeAuthenticationList()
	{
		//	读取字典文件
		String userDic = proxy.getUserDic();
		String passDic = proxy.getPassDic();
		List <String> userNames = new ArrayList <String>();
		List <String> passwords = new ArrayList <String>();
		FileReader userReader = null;
		BufferedReader userBufReader = null;
		FileReader passReader = null;
		BufferedReader passBufReader = null;
		try
		{
			userReader = new FileReader(userDic);
			userBufReader = new BufferedReader(userReader);
			while(true)
			{
				String user = userBufReader.readLine();
				if(user == null)
				{
					break;
				}
				else if(user.equals(""))
				{
					continue;
				}

				userNames.add(user);
			}

			passReader = new FileReader(passDic);
			passBufReader = new BufferedReader(passReader);
			while(true)
			{
				String pass = passBufReader.readLine();
				if(pass == null)
				{
					break;
				}
				else if(pass.equals(""))
				{
					continue;
				}

				passwords.add(pass);
			}
		}
		catch (FileNotFoundException e)
		{
			e.printStackTrace();
			return false;
		}
		catch (IOException e)
		{
			e.printStackTrace();
			return false;
		}
		finally
		{
			try
			{
				userReader.close();
				userBufReader.close();
				passReader.close();
				passBufReader.close();
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}

		//	组合生成验证信息对列表
		if(! proxy.isReversedMode())
		{
			Iterator itUser = userNames.iterator();
			while(itUser.hasNext())
			{
				String u = (String) itUser.next();
				Iterator itPass = passwords.iterator();
				while(itPass.hasNext())
				{
					String p = (String) itPass.next();
					AuthenticationPair authPair = new AuthenticationPair();
					authPair.setUserName(u);
					authPair.setPassword(characterEscape(p, u));
					authList.pushBack(authPair);
				}
			}
		}
		else
		{
			Iterator itPass = passwords.iterator();
			while(itPass.hasNext())
			{
				String p = (String) itPass.next();
				Iterator itUser = userNames.iterator();
				while(itUser.hasNext())
				{
					String u = (String) itUser.next();
					AuthenticationPair authPair = new AuthenticationPair();
					authPair.setUserName(u);
					authPair.setPassword(characterEscape(p, u));
					authList.pushBack(authPair);
				}
			}
		}

		totalSize = authList.getSize();
		return true;
	}

	//	处理转义字符
	private String characterEscape(String pass, String user)
	{
		String tmp = pass.replaceAll("%NULL%", "");
		tmp = tmp.replaceAll("%USER%", user);
		tmp = tmp.replaceAll("%%", "%");

		return tmp;
	}
}
